const PADDING = "PADDING";
const SUCCESS = "FULFILLED";
const FAILD = "REJECTED";

function resolvePromise(promise2, x, resolve, reject) {
    if (promise2 === x) {
        return reject(new TypeError("TypeError"));
    }
    //按x判断类型
    //promise有n种实现都符合了这个规范 兼容别人的promise

    let called;
    //怎么判断 x是不是一个promise 看她有没有then方法
    if (typeof x === "function" || (typeof x === "object" && x !== null)) {
        try {
            let then = x.then; //取then方法可能出错
            if (typeof then === "function") {
                //就认为她是一个promise
                then.call(
                    x,
                    y => {
                        if (called) return;//1)
                        called = true;
                        //如果promise是成功就把结果向下传,如果失败就让下一个也失败
                        resolvePromise(promise2, y, resolve, reject); //递归
                    },
                    r => {
                        if (called) return;//2)
                        called = true;
                        reject(r);
                    }
                ); //不要使用x.then 否则会再次取值
            } else {
                //then:()=>{}
                resolve(x);
            }
        } catch (e) {
            if (called) return;//3)为了辨别这个promise不能调用多次
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
}

class MyPromise {
    constructor(executor) {
        this.status = PADDING;
        this.value = undefined;
        this.reason = undefined;
        this.resolveList = [];
        this.rejectList = [];

        const resolve = value => {
            if (this.status === PADDING) {
                this.status = SUCCESS;
                this.value = value;
                this.resolveList.forEach(fn => fn());
            }
        };

        const reject = reason => {
            if (this.status === PADDING) {
                this.status = FAILD;
                this.reason = reason;
                this.rejectList.forEach(fn => fn());
            }
        };

        executor(resolve, reject);
    }

    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {

            if (this.status === SUCCESS) {
                // resolve(onFulfilled(this.value));
                try{
                    let x = onFulfilled(this.value);
                    resolvePromise(this,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            }

            if (this.status === FAILD) {
                // onRejected(this.reason);
                try{
                    let x = onRejected(this.reason);
                    resolvePromise(this,x,resolve,reject)
                }catch(e){
                    reject(e);
                }
            }

            if (this.status === PADDING) {
                this.resolveList.push(() => {
                    //   onFulfilled(this.value);
                    try{
                        let x = onFulfilled(this.value);
                        // resolve(x)
                        resolvePromise(this,x,resolve,reject)
                    }catch(e){
                        reject(e);
                    }

                });
                this.rejectList.push(() => {
                    // onRejected(this.reason);
                    reject(onRejected(this.reason));
                    //   try{
                    //     let x = onRejected(this.value);
                    //     // resolve(x)
                    //     resolvePromise(this,x,resolve,reject)
                    //   }catch(e){
                    //     reject(e);
                    //   }
                });
            }
        });
    }
}

module.exports = MyPromise;
